package com.starleague.battletech.unit.mech;

import com.starleague.battletech.BattletechException;
import com.starleague.battletech.unit.BattletechUnitInternalStructureType;
import com.starleague.battletech.unit.IWeight;
import com.starleague.battletech.unit.ImmutableWeight;

public abstract class AbstractMechInternalStructureFactory
{
    public final IMechInternalStructure addInternalStructure(IMutableMech mech,
                                                             BattletechUnitInternalStructureType internalStructureType)
            throws BattletechException
    {
        IWeight internalStructureWeight = calcInternalStructureWeight(mech, internalStructureType);
        return addInternalStructure(mech, internalStructureWeight, internalStructureType);
    }

    public int getInternalStructurePointsForHitLocationType(IMutableMech mech,
                                                            MechHitLocationType hitLocationType)
            throws BattletechException
    {
        return getInternalStructurePointsForHitLocationType(getInternalStructurePointsRecord(mech), hitLocationType);
    }

    protected abstract IMechInternalStructure addInternalStructure(IMutableMech mech,
                                                                   IWeight internalStructureWeight,
                                                                   BattletechUnitInternalStructureType internalStructureType)
            throws BattletechException;

    private IWeight calcInternalStructureWeight(IMutableMech mech,
                                                BattletechUnitInternalStructureType internalStructureType)
            throws BattletechException
    {
        switch (internalStructureType)
        {
            case NORMAL:
                // TODO: Check Rounding!
                return new ImmutableWeight(mech.getWeight().getTons() * 0.1);

            case ENDO_IS:
            case ENDO_CLAN:
                // TODO: Check Rounding!
                return new ImmutableWeight(mech.getWeight().getTons() * 0.05);
                // this.ctons = ((i_mech_tons + 9) / 10) * 50;
        }
        throw new BattletechException("Unknown BattletechUnitInternalStructureType: " + internalStructureType);
    }

    private static int getInternalStructurePointsForHitLocationType(int internalStructurePointsRecord[],
                                                                    MechHitLocationType hitLocationType)
            throws BattletechException
    {
        switch (hitLocationType)
        {
            case ARM:
                return internalStructurePointsRecord[3];

            case CENTER_TORSO:
                return internalStructurePointsRecord[1];

            case HEAD:
                return internalStructurePointsRecord[0];

            case LEG:
                return internalStructurePointsRecord[4];

            case SIDE_TORSO:
                return internalStructurePointsRecord[2];
        }
        throw new BattletechException("Unknown MechHitLocationType: " + hitLocationType);
    }

    private static int[] getInternalStructurePointsRecord(IMech mech) throws BattletechException
    {
        int weightAsInteger = mech.getWeight().getTonsAsInteger();
        if ((weightAsInteger % 5) != 0)
            throw new BattletechException("Mech weight [" + mech.getWeight() + "] is not divisible by 5");

        int internalStructurePointsChartIndex = weightAsInteger / 5;

        if ((internalStructurePointsChartIndex < 0)
            || (internalStructurePointsChartIndex >= internalStructurePointsChart.length)
            || (internalStructurePointsChart[internalStructurePointsChartIndex] == null))
            throw new BattletechException("Mech weight [" + mech.getWeight() + "] is out of range");

        return internalStructurePointsChart[internalStructurePointsChartIndex];
    }

    /**
     * Internal_structure points a mech has, by [weight / 5]
     * { HEAD, CENTER_TORSO, SIDE_TORSO, ARM, LEG }
     */
    private final static int[][] internalStructurePointsChart = {
            // the first 4 values are not valid for basic Battletech. IE: More to come!
            null, // mech tonnage of 0 is invalid
            null, // mech tonnage of 5 is invalid
            null, // mech tonnage of 10 is invalid { 3, 4, 3, 1, 2 },
            null, // mech tonnage of 15 is invalid { 3, 5, 4, 2, 3 },
            { 3, 6, 5, 3, 4 }, // 20 tons
            { 3, 8, 6, 4, 6 },
            { 3, 10, 7, 5, 7 },
            { 3, 11, 8, 6, 8 },
            { 3, 12, 10, 6, 10 },
            { 3, 14, 11, 7, 11 },
            { 3, 16, 12, 8, 12 },
            { 3, 18, 13, 9, 13 },
            { 3, 20, 14, 10, 14 },
            { 3, 21, 15, 10, 15 },
            { 3, 22, 15, 11, 15 }, // 70 tons
            { 3, 23, 16, 12, 16 },
            { 3, 25, 17, 13, 17 },
            { 3, 27, 18, 14, 18 },
            { 3, 29, 19, 15, 19 },
            { 3, 30, 20, 16, 20 },
            { 3, 31, 21, 17, 21 }, // 100 tons
    // { 105, 4, 32, 22, 17, 22 },
    // { 110, 4, 33, 23, 18, 23 },
    // { 115, 4, 35, 24, 19, 24 },
    // { 120, 4, 36, 25, 20, 25 },
    // { 125, 4, 38, 26, 21, 26 },
    // { 130, 4, 39, 27, 21, 27 },
    // { 135, 4, 41, 28, 22, 28 },
    // { 140, 4, 42, 29, 23, 29 },
    // { 145, 4, 44, 31, 24, 31 },
    // { 150, 4, 45, 32, 25, 32 },
    // { 155, 4, 47, 33, 26, 33 },
    // { 160, 4, 48, 34, 26, 34 },
    // { 165, 4, 50, 35, 27, 35 },
    // { 170, 4, 51, 36, 28, 36 },
    // { 175, 4, 53, 37, 29, 37 },
    // { 180, 4, 54, 38, 30, 38 },
    // { 185, 4, 56, 39, 31, 39 },
    // { 190, 4, 57, 40, 31, 40 },
    // { 195, 4, 59, 41, 32, 41 },
    // { 200, 4, 60, 42, 33, 42 }
    };
}
